package com.lin.manager.secure.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lin.manager.log.enums.LogEnum;
import com.lin.manager.log.ex.CustomLogException;
import com.lin.manager.log.service.LogService;
import com.lin.manager.secure.enums.SecurityEnum;
import com.lin.manager.secure.ex.CustomAuthenticationException;
import com.lin.manager.secure.model.SecurityLog;
import com.lin.manager.secure.model.SecurityUser;
import com.lin.manager.secure.token.AccessTokenService;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @作者: 林江
 * @创建时间: 2024/1/3
 * @功能: 认证成功或失败的处理方式
 */
public class SecurityHandler implements LogoutSuccessHandler, AuthenticationSuccessHandler, AuthenticationFailureHandler {
    /**
     * 是否开启登录日志
     */
    private Boolean isLog = false;
    private ObjectMapper objectMapper = new ObjectMapper();
    private AccessTokenService accessTokenService;
    private LogService logService;

    public void setTokenService(AccessTokenService accessTokenService) {
        this.accessTokenService = accessTokenService;
    }

    public void setLogService(LogService logService) {
        this.isLog = true;
        this.logService = logService;
    }

    // 失败之后的处理
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        // 设置token
        Map<String, Object> map = new HashMap<>();
        map.put("code", HttpStatus.FORBIDDEN.value());
        if (exception instanceof CustomAuthenticationException) {
            map.put("msg", exception.getMessage());
        } else if (exception instanceof UsernameNotFoundException ||
                exception instanceof BadCredentialsException) {
            map.put("msg", SecurityEnum.LOGIN_FAIL_USERNAME_PASSWORD.getDesc());
        } else {
            map.put("msg", SecurityEnum.LOGIN_FAIL.getDesc());
            map.put("data", exception.getMessage());
        }

        if (isLog) {
            this.addSecurityLog(SecurityLog.builder()
                    .id(System.currentTimeMillis())
                    .descript(map.get("msg").toString())
                    .createTime(new Date())
                    .status(Objects.equals(map.get("code").toString(), HttpStatus.OK.value() + "") ? 0 : 1)
                    .build()
            );
        }

        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(map));
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException {
        try {
            SecurityUser user = (SecurityUser) auth.getPrincipal();
            // 设置token
            Map<String, Object> map = new HashMap<>();
            map.put("code", HttpStatus.OK.value());
            map.put("msg", SecurityEnum.LOGIN_SUCCESS.getDesc());

            // 创建token
            String token = accessTokenService.createToken(user);
            map.put("data", token);

            // 登录成功，日志收集
            if (isLog) {
                this.addSecurityLog(SecurityLog.builder()
                        .id(System.currentTimeMillis())
                        .userName(user.getUsername())
                        .descript(map.get("msg").toString())
                        .createTime(new Date())
                        .status(Objects.equals(map.get("code").toString(), HttpStatus.OK.value() + "") ? 0 : 1)
                        .build()
                );
            }

            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().println(objectMapper.writeValueAsString(map));
        } catch (Exception e) {
            e.printStackTrace();
            this.onAuthenticationFailure(request, response, new UsernameNotFoundException("登录用户获取权限失败，异常【" + e.getMessage() + "】"));
        }
    }

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> map = new HashMap<>();
        map.put("code", HttpStatus.OK.value());
        map.put("msg", "退出成功");
        map.put("data", null);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(objectMapper.writeValueAsString(map));
    }


    public void addSecurityLog(SecurityLog securityLog) {
        if (Objects.isNull(logService)) {
            throw new CustomLogException(LogEnum.LOG_SERVICE_NOT_EXIST);
        }

        logService.addLog(securityLog);
    }
}
